/********************************************************************************
 * Copyright (c) 2017, 2018 Bosch Connected Devices and Solutions GmbH.
 * 
 * This program and the accompanying materials are made available under the
 * terms of the Eclipse Public License 2.0 which is available at
 * http://www.eclipse.org/legal/epl-2.0.
 * 
 * Contributors:
 *    Bosch Connected Devices and Solutions GmbH - initial contribution
 * 
 * SPDX-License-Identifier: EPL-2.0
 ********************************************************************************/

/*
 * generated by Xtext 2.10.0
 */
package org.eclipse.mita.program.ui.quickfix

import com.google.inject.Inject
import org.eclipse.mita.base.expressions.ElementReferenceExpression
import org.eclipse.mita.base.expressions.ExpressionsFactory
import org.eclipse.mita.base.expressions.ExpressionsPackage
import org.eclipse.mita.base.expressions.FeatureCall
import org.eclipse.mita.base.types.TypesFactory
import org.eclipse.mita.base.types.typesystem.ITypeSystem
import org.eclipse.mita.base.typesystem.BaseConstraintFactory
import org.eclipse.mita.base.ui.quickfix.TypeDslQuickfixProvider
import org.eclipse.mita.base.util.BaseUtils
import org.eclipse.mita.library.^extension.LibraryExtensions
import org.eclipse.mita.program.Program
import org.eclipse.mita.program.ProgramFactory
import org.eclipse.mita.program.SystemResourceSetup
import org.eclipse.mita.program.generator.DefaultValueProvider
import org.eclipse.mita.program.validation.ProgramImportValidator
import org.eclipse.mita.program.validation.ProgramSetupValidator
import org.eclipse.xtext.naming.QualifiedName
import org.eclipse.xtext.scoping.IScopeProvider
import org.eclipse.xtext.ui.editor.quickfix.Fix
import org.eclipse.xtext.ui.editor.quickfix.IssueResolutionAcceptor
import org.eclipse.xtext.validation.Issue
import org.eclipse.mita.program.generator.transformation.AbstractTransformationStage
import org.eclipse.emf.ecore.util.EcoreUtil

class ProgramDslQuickfixProvider extends TypeDslQuickfixProvider {

	@Inject
	protected IScopeProvider scopeProvider;
	
	@Inject
	protected ITypeSystem typeSystem;
		
	@Inject
	DefaultValueProvider defaultValueProvider

	@Fix(BaseConstraintFactory.FUNCTION_CANNOT_BE_USED_HERE)
	def migrateScopeToFeatureCallWithoutFeature(Issue issue, IssueResolutionAcceptor acceptor) {
		val uri = issue.uriToProblem;
		if(uri.toString.contains("@setup.")) {
			acceptor.accept(issue, "Try to migrate to new type system", "In setup blocks enum and sum type constructors can no longer be directly used. Instead you can use a new calling style which is just as easy to use.", "", 
				[element, context |
					if(element instanceof ElementReferenceExpression) {
						if(element instanceof FeatureCall) {
							return;
						}
						val ref = ExpressionsPackage.eINSTANCE.elementReferenceExpression_Reference;
						val referencedElementName = BaseUtils.getText(element, ref);
						val scope = scopeProvider.getScope(element, ref);
						val candidates = scope.getElements(QualifiedName.create(referencedElementName));
						if(candidates.size == 1) {
							val candidate = candidates.head.EObjectOrProxy;
							val fcwf = ExpressionsFactory.eINSTANCE.createFeatureCallWithoutFeature;
							fcwf.reference = candidate;
							fcwf.arguments += element.arguments;
							fcwf.operationCall = true;
							AbstractTransformationStage.replaceWith(element, fcwf);
						}
					}	
				])
		}
	}

	@Fix(ProgramSetupValidator.MISSING_CONIGURATION_ITEM_CODE)
	def addMissingConfigItem(Issue issue, IssueResolutionAcceptor acceptor) {
		acceptor.accept(issue, 'Add config items', 'Add missing configuration items', '', [ element, context |

			val setup = element as SystemResourceSetup
			setup.type.configurationItems.filter[required] // item is mandatory
			.filter[!setup.configurationItemValues.map[c|c.item].contains(it)] // item is not contained in setup
			.forEach [ missingItem | // create dummy value
				val newConfigItemValue = ProgramFactory.eINSTANCE.createConfigurationItemValue
				setup.configurationItemValues.add(newConfigItemValue)
				newConfigItemValue.item = missingItem
				newConfigItemValue.value = defaultValueProvider.dummyExpression(missingItem.type, newConfigItemValue)
			]
		])
	}

	@Fix(ProgramImportValidator.NO_PLATFORM_SELECTED_CODE)
	def addMissingPlatform(Issue issue, IssueResolutionAcceptor acceptor) {
		LibraryExtensions.availablePlatforms.forEach [ platform |
			acceptor.accept(issue, '''Import '«platform.id»' '''.toString,
				'''Add import for platform '«platform.id»' '''.toString, '', [ element, context |
					val program = element as Program
					program.imports += TypesFactory.eINSTANCE.createImportStatement => [
						importedNamespace = platform.id
					]
				])
		]
	}

	@Fix(ProgramImportValidator.MULTIPLE_PLATFORMS_SELECTED_CODE)
	def addMissingPlatform2(Issue issue, IssueResolutionAcceptor acceptor) {
		acceptor.accept(issue, '''Remove all imports except: «issue.data.toString»''', "", "", [element, context | 
			val program = element.eContainer as Program
			EcoreUtil.removeAll(program.imports.filter[it != element].toList)
		])
		acceptor.accept(issue, '''Remove import: «issue.data.toString»''', "", "",[element ,context | EcoreUtil.remove(element)])
	}
}
